import { ipcMain, BrowserWindow } from 'electron'
import { throttle } from 'lodash-es'
// IPC事件名常量（统一管理，避免硬编码）
const IPC_DRAG_EVENTS = {
  GET_WINDOW_ID: 'window-drag:get-window-id',
  START: 'window-drag:start',
  MOVE: 'window-drag:move',
  END: 'window-drag:end'
} as const

const setupSmoothDrag = (): void => {
  // 存储拖拽状态（包含窗口实例和清理函数，防止内存泄漏）
  const dragState = new Map<
    number,
    {
      startMouseX: number
      startMouseY: number
      startWindowX: number
      startWindowY: number
      window: BrowserWindow
      cleanup: () => void
    }
  >()

  // 节流处理窗口移动（8ms间隔，平衡流畅度与性能）
  const throttledHandleMove: ReturnType<typeof throttle> = throttle(
    (window: BrowserWindow, currentMouseX: number, currentMouseY: number, windowId: number) => {
      // 二次校验：防止节流函数触发时窗口已销毁或状态已清理
      const state = dragState.get(windowId)
      if (!state || window.isDestroyed() || !dragState.has(windowId)) {
        throttledHandleMove.cancel()
        return
      }

      // 校验窗口尺寸是否正常（避免异常值导致位置计算错误）
      const currentBounds = window.getBounds()
      if (currentBounds.width <= 0 || currentBounds.height <= 0) {
        console.warn('[拖拽警告] 窗口尺寸异常，跳过位置更新')
        return
      }

      // 基于绝对位置计算新坐标（避免累计误差）
      const newWindowX = state.startWindowX + (currentMouseX - state.startMouseX)
      const newWindowY = state.startWindowY + (currentMouseY - state.startMouseY)

      // 位置有变化时才更新（减少无效操作）
      if (newWindowX !== currentBounds.x || newWindowY !== currentBounds.y) {
        window.setBounds(
          {
            ...currentBounds,
            x: newWindowX,
            y: newWindowY
          },
          false
        )
      }
    },
    8,
    { leading: true, trailing: true } // 显式指定节流行为（兼容不同lodash版本）
  )

  // 获取当前窗口ID（带类型安全处理）
  ipcMain.handle(IPC_DRAG_EVENTS.GET_WINDOW_ID, (event) => {
    const window = BrowserWindow.fromWebContents(event.sender)
    return window?.id ?? -1 // 无效窗口返回-1（避免null导致渲染端错误）
  })

  // 拖拽开始：初始化状态并绑定清理逻辑
  ipcMain.on(
    IPC_DRAG_EVENTS.START,
    (_, windowId: unknown, startMouseX: unknown, startMouseY: unknown) => {
      // 严格参数校验（防止渲染端传错值）
      if (typeof windowId !== 'number' || windowId <= 0 || !Number.isInteger(windowId)) {
        console.error('[拖拽错误] windowId必须是正整数')
        return
      }
      if (
        typeof startMouseX !== 'number' ||
        typeof startMouseY !== 'number' ||
        isNaN(startMouseX) ||
        isNaN(startMouseY)
      ) {
        console.error('[拖拽错误] 鼠标坐标必须是有效数字')
        return
      }

      // 获取窗口实例并校验有效性
      const window = BrowserWindow.fromId(windowId)
      if (!window || window.isDestroyed()) {
        console.error('[拖拽错误] 窗口不存在或已销毁')
        return
      }

      // 清理旧状态（防止重复拖拽导致的状态残留）
      if (dragState.has(windowId)) {
        const oldState = dragState.get(windowId)!
        oldState.window.off('closed', oldState.cleanup)
        dragState.delete(windowId)
      }

      // 定义窗口关闭时的清理逻辑
      const cleanup = () => {
        dragState.delete(windowId)
        throttledHandleMove.cancel()
      }

      // 记录初始状态（鼠标+窗口绝对位置）
      const [winX, winY] = window.getPosition()
      dragState.set(windowId, {
        startMouseX,
        startMouseY,
        startWindowX: winX,
        startWindowY: winY,
        window,
        cleanup
      })

      // 监听窗口关闭事件（确保意外关闭时清理状态）
      window.once('closed', cleanup)

      // 窗口行为优化（跨平台置顶+焦点）
      window.setAlwaysOnTop(true, 'pop-up-menu') // 优先级确保窗口在最上层
      window.focus()
      window.setResizable(false) // 拖拽时禁用缩放
    }
  )

  // 拖拽移动：实时更新窗口位置
  ipcMain.on(
    IPC_DRAG_EVENTS.MOVE,
    (_, windowId: unknown, currentMouseX: unknown, currentMouseY: unknown) => {
      // 参数校验
      if (typeof windowId !== 'number' || windowId <= 0 || !Number.isInteger(windowId)) return
      if (
        typeof currentMouseX !== 'number' ||
        typeof currentMouseY !== 'number' ||
        isNaN(currentMouseX) ||
        isNaN(currentMouseY)
      )
        return

      // 窗口实例校验
      const window = BrowserWindow.fromId(windowId)
      if (!window || window.isDestroyed() || !dragState.has(windowId)) return

      // 确保窗口焦点（跨屏时防止焦点丢失）
      if (!window.isFocused()) {
        window.focus()
      }

      // 触发节流移动逻辑
      throttledHandleMove(window, currentMouseX, currentMouseY, windowId)
    }
  )

  // 拖拽结束：清理状态并恢复窗口行为
  ipcMain.on(IPC_DRAG_EVENTS.END, (_, windowId: unknown,sizable:boolean = true) => {
    // 参数校验
    if (typeof windowId !== 'number' || windowId <= 0 || !Number.isInteger(windowId)) return

    // 清理状态
    const state = dragState.get(windowId)
    if (state) {
      state.window.off('closed', state.cleanup) // 移除关闭监听
      dragState.delete(windowId)
    }

    // 恢复窗口状态
    const window = BrowserWindow.fromId(windowId)
    if (window && !window.isDestroyed() && sizable) {
      window.setResizable(true)
      window.setAlwaysOnTop(false) // 取消置顶
    }

    // 取消节流残留调用
    throttledHandleMove.cancel()
  })
}

export default {
  setupSmoothDrag
}
